<?php

namespace common\service\step_category_month_report;

use common\model\PlanModel;
use common\model\TaskModel;
use common\model\EntityModel;
use common\model\TaskWorkOrderModel;
use common\service\StatusService;

/**
 * 实体环节任务统计 实体个数
 */
class EntityReportCount extends EpisodeReportCountBase
{

    protected $planDonePlanData = [];

    public function getPlanDonePlanData($projectId, $monthStart, $monthEnd, $stepCategoryIdList)
    {
        if (!empty($this->planDonePlanData)) {
            return $this->planDonePlanData;
        }
        $this->planDonePlanData = model(PlanModel::class)
            ->alias('p')
            ->join('task_relation_tag r_step_category on p.task_id = r_step_category.task_id')
            ->where(['p.project_id' => $projectId])
            ->where(['p.type' => PlanModel::TYPE_STEP_CATEGORY, 'p.scope' => PlanModel::SCOPE_SINGLE])
            ->where([['p.end_time' => ['EGT', $monthStart]], ['p.end_time' => ['ELT', $monthEnd]]])
            ->where(['r_step_category.link_module_code' => ['IN', ['step_category', 'show_step_category']]])
            ->where(['r_step_category.link_id' => ['IN', implode(',', $stepCategoryIdList)]])
            ->field('p.entity_id episode_id,r_step_category.link_id as step_category_id,p.end_time,p.start_time')
            ->group('p.entity_id,r_step_category.link_id')
            ->cache(APP_DEBUG ? false : C('database.default_query_cache_time'))
            ->select();
        return $this->planDonePlanData;
    }

    /**
     * 计算统计数据
     * @param $projectId
     * @param $stepCategoryIdList
     * @param $monthStart
     * @param null $monthEnd
     * @return void
     */
    public function calculate($projectId, $stepCategoryIdList, $monthStart, $monthEnd = null)
    {
        $this->countObject = new StepCategoryMonthCountObject();
        $monthStart = strtotime($monthStart);
        if (empty($monthEnd)) {
            $monthEnd = strtotime("+1 month -1 second", $monthStart);
        } else {
            $monthEnd = strtotime($monthEnd);
            $this->countObject->canBeSaved = false;
        }
        $this->countObject->deliveryUnit = '个';
        $this->countObject->projectId = $projectId;
        $this->countObject->tenantId = request()->getTenantId();
        $this->countObject->monthTime = $monthStart;
        $this->countObject->stepCategoryIds = implode(',', $stepCategoryIdList);

        $planData = $this->getPlanDonePlanData($projectId, $monthStart, $monthEnd, $stepCategoryIdList);
        if (empty($planData)) {
            $this->countObject->havePlan = false;
            return;
        }
        $episodeStepCategoryFilter = [];
        $planTimeLimitMap = [];
        foreach ($planData as $datum) {
            $episodeStepCategoryFilter[] = ["task.episode_id" => $datum['episode_id'], 'task.step_category_id' => $datum['step_category_id']];
            $planTimeLimitMap[$datum['episode_id'] . '-' . $datum['step_category_id']] = $datum;
        }
        $episodeStepCategoryFilter['_logic'] = 'OR';
        $episodeStepCategoryFilter = [$episodeStepCategoryFilter];
        $closedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();
        $episodeStepCategoryFilter[] = ["task.json->>'$.task_status'" => ['NEQ', $closedStatus['id']]];

        $planDoneTaskList = model(EntityModel::class)
            ->join('task on task.entity_id = entity.id')
            ->join("version on version.module_id = " . module_by_code('task')['id'] . " and version.link_id = task.id", 'LEFT')
            ->where(['task.step_type' => TaskModel::STEP_TYPE_STEP])
            ->where($episodeStepCategoryFilter)
            ->field('task.id,entity.is_append,task.entity_id,task.end_time,task.plan_end_time,task.step_category_id,task.episode_id,count(version.is_publish="yes" or null) published_number')
            ->group('task.id')
            ->cache(APP_DEBUG ? false : C('database.default_query_cache_time'))
            ->select();

        $totalEntityIdList = [];
        $appendEntityIdList = [];
        $deliveryEntityIdList = [];
        $abnormalEntityIdList = [];
        $publishedOneTimesEntityIdList = [];
        $planDoneTaskListGrouped = array_group_by($planDoneTaskList, 'entity_id');
        foreach ($planDoneTaskListGrouped as $entityId => $planDoneTaskList) {
            $totalEntityIdList[$entityId] = $entityId;
            $isAppend = false;
            $publishedTaskCount = 0;
            $entityTaskCount = count($planDoneTaskList);
            $entityPublishOneTimeTaskCount = 0;
            $hasAbnormal = false;
            foreach ($planDoneTaskList as $planDoneTaskItem) {
                if ($planDoneTaskItem['is_append'] === 'yes') {
                    $isAppend = true;
                }
                // 月结束前交付才算本月交付
                if ($planDoneTaskItem['published_number'] > 0 && $planDoneTaskItem['end_time'] <= $monthEnd) {
                    $publishedTaskCount += 1;
                    if ($planDoneTaskItem['published_number'] == 1) {
                        $entityPublishOneTimeTaskCount += 1;
                    }
                }
                $k = $planDoneTaskItem['episode_id'] . '-' . $planDoneTaskItem['step_category_id'];
                if (
                    !$hasAbnormal &&
                    !empty($planTimeLimitMap[$k]['end_time'])
                    && $planTimeLimitMap[$k]['end_time'] > 0
                    && (
                        ($planDoneTaskItem['end_time'] > 0 && $planDoneTaskItem['end_time'] > $planTimeLimitMap[$k]['end_time'])
                        || ($planDoneTaskItem['end_time'] == 0 && $planTimeLimitMap[$k]['end_time'] <= $monthEnd)
                    )
                ) {
                    $hasAbnormal = true;
                }
            }
            if ($isAppend) {
                $appendEntityIdList[$entityId] = $entityId;
            }
            if ($publishedTaskCount === $entityTaskCount) {
                $deliveryEntityIdList[$entityId] = $entityId;
            }
            if ($hasAbnormal) {
                $abnormalEntityIdList[$entityId] = $entityId;
            }
            if ($entityPublishOneTimeTaskCount === $entityTaskCount) {
                $publishedOneTimesEntityIdList[$entityId] = $entityId;
            }
        }

        $this->countObject->shouldDelivery = count($totalEntityIdList);
        $this->countObject->addDelivery = count($appendEntityIdList);
        $this->countObject->planDelivery = $this->countObject->shouldDelivery - $this->countObject->addDelivery;
        $this->countObject->delivery = count($deliveryEntityIdList);
        // 没有按计划完成的计划完成任务数
        $this->countObject->abnormal = count($abnormalEntityIdList);
        // 通过率
        $this->countObject->deliveryNoRepair = count($publishedOneTimesEntityIdList);
        if ($this->countObject->delivery > 0) {
            $this->countObject->passPercent = $this->countObject->deliveryNoRepair / $this->countObject->delivery;
        }

        $taskWorkOrderList = model(TaskWorkOrderModel::class)
            ->alias('two')
            ->join('task t on t.id = two.task_id')
            ->where(['two.project_id' => $projectId, 'two.created' => ['BETWEEN', [$monthStart, $monthEnd]]])
            ->group('two.id,t.entity_id,t.step_category_id')
            ->field('two.id,t.entity_id,t.step_category_id')
            ->cache(APP_DEBUG ? false : C('database.default_query_cache_time'))
            ->select();

        $stepCategoryEntityIdList = [];
        foreach ($taskWorkOrderList as $taskWorkOrderItem) {
            if (in_array($taskWorkOrderItem['step_category_id'], $stepCategoryIdList)) {
                $stepCategoryEntityIdList[$taskWorkOrderItem['entity_id']] = $taskWorkOrderItem['entity_id'];
            }
        }
        $this->countObject->taskWorkOrderPercent = 0;
        $this->countObject->currentWorkOrderNumber = count($stepCategoryEntityIdList);
        $this->countObject->workOrderNumber = count($taskWorkOrderList);
        if (!empty($this->countObject->workOrderNumber)) {
            $this->countObject->taskWorkOrderPercent = $this->countObject->currentWorkOrderNumber / $this->countObject->workOrderNumber;
        }
        // 交付率
        $this->setDeliveryPercent();
        $this->setIsPlanDone();
        $this->saveCountObjectData();
    }
}
